#include "cmdselectdatafromdb.h"
#include "cmdsql.h"
#include "commclassdb.h"
#include "dbctrl.h"

CT_REGISTER_ASYNCCMD(ID_MAINDB_SELECTDATA, CCmdSelectDataFromDB);

char CCmdSelectDataFromDB::szBuf[CTMsgHead::EMAX_MSGLEN];

CCmdSelectDataFromDB::CCmdSelectDataFromDB()
    :_bHasOtherData(false), _iFrom(0)
{

}

CCmdSelectDataFromDB::~CCmdSelectDataFromDB()
{

}

int CCmdSelectDataFromDB::Do(void* pData)
{
    int iRet = 0;

    if (!pData)
    {
        CT_WARNING((""));
        return Done(RET_SYSTEM_FAIL);
    }

    //解析请求
    CCmdDoParam* pstParam = (CCmdDoParam*) pData;
    if (pstParam->m_pMain == NULL ||
        pstParam->m_pstMsgHead->shMsgID != ID_MAINDB_SELECTDATA ||
        pstParam->m_pstMsgHead->shMsgType != CTLib::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Tpye=%d",
            ID_MAINDB_SELECTDATA,
            pstParam->m_pstMsgHead->shMsgID,
            pstParam->m_pstMsgHead->shMsgType));
        return Done(RET_SYSTEM_FAIL);
    }

    m_stHead = *pstParam->m_pstHead;
    m_stMsgHead = *pstParam->m_pstMsgHead;
    pstMainCtrl = (CDBCtrl*)pstParam->m_pMain;

    iRet = CodeConvert(*pstParam->m_pstCode, stReq, NULL, bin_decode());
    if (iRet != 0)
    {
        CT_WARNING((""));
        return AnsClients(iRet);
    }

    //刷数据通知
    if (DT_FLUSH_DBSVR_DATA == stReq.m_stKey.m_chDataType)
    {
        if(!pstMainCtrl->m_stUpdateMgr.CheckEmpty())
        {
            bool bIsSwap = false;
            pstMainCtrl->m_stUpdateMgr.CheckSwap(1, time(0), 10, &bIsSwap);    
        }

        CTCodeStream s(szBuf, sizeof(szBuf));
        unsigned char ucIsEmpty = pstMainCtrl->m_stUpdateMgr.CheckEmpty() ? 1 : 0;
        CodeConvert(s, ucIsEmpty, NULL, bin_encode());
        stAns.iDataLen = (int)s.m_ushPos;
        iRet = AnsResult(s.m_iRet);
        return AnsClients(iRet);
    }

    CT_TRACE(("begin select data"));

    if (stReq.m_ucCheckUpdateMgr != 0)
    {
        CVarObjectHead stVarObjectHead;
        iRet = pstMainCtrl->GetDataFromUpdateMgr(stReq.m_stKey, szBuf, sizeof(szBuf), stVarObjectHead);
        if (iRet == 0) //找到数据
        {
            stAns.iDataLen = stVarObjectHead.m_iDataLen;
            iRet = AnsResult(RET_OK);
            return AnsClients(iRet);
        }
    }

    //GID
    if (stReq.m_stKey.m_chDataType == DT_PLAYER_GID)
    {
        CTSizeString<USER_TOKEN_LEN> szUserToken;
        szUserToken.Set("%s", stReq.m_stKey.m_sStrID());
        int iIndex = CDBCtrl::m_pstMain->m_stUserTokenToGID.HashFind(szUserToken);
        if (iIndex >= 0)
        {
            CTCodeStream s(szBuf, sizeof(szBuf));
            CodeConvert(s, CDBCtrl::m_pstMain->m_stUserTokenToGID[iIndex], NULL, bin_encode());
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(s.m_iRet);
            return AnsClients(iRet);
        }
    }

    iRet = SendSql();
    if (iRet != RET_OK)
    {
        iRet = AnsResult(iRet);
        return AnsClients(iRet);
    }

    return 0;
}

int CCmdSelectDataFromDB::SendSql()
{
    int iRet = 0;
    //没有找到则继续执行
    CCmdSQL* pstCmd = (CCmdSQL*)CT_CMDFACTORY->CreateCmd(ID_DB_SQL);
    if (!pstCmd)
    {
        CT_WARNING((""));
        return RET_SYSTEM_FAIL;
    }

    iRet = BuildSql(pstCmd);
    if (iRet != RET_OK)
    {
        CT_WARNING(("ret %d", iRet));
        return RET_SYSTEM_FAIL;
    }

    pstCmd->m_pstMain = pstMainCtrl;
    RegisterChild(pstCmd);

    CEnpNetHead stHead;
    iRet = pstCmd->Do(&stHead);
    if (iRet != 0)
    {
        CT_WARNING((""));
        return RET_OK;  //在CALL BACK里面处理错误
    }
    
    return 0;
}

int CCmdSelectDataFromDB::CallBack(int iRet)
{
    CT_TRACE(("mp callback"));
    if (iRet)
    {       
        iRet = AnsResult(iRet);
        return AnsClients(iRet);
    }

    CT_ASSERT(m_pstChild);

    if (stReq.m_ucCheckUpdateMgr != 0)
    {
        CVarObjectHead stVarObjectHead;
        iRet = pstMainCtrl->GetDataFromUpdateMgr(stReq.m_stKey, szBuf, sizeof(szBuf), stVarObjectHead);
        if (iRet == 0) //找到数据
        {
            stAns.iDataLen = stVarObjectHead.m_iDataLen;
            iRet = AnsResult(RET_OK);
            return AnsClients(iRet);
        }
    }

    //没有找到则继续执行
    CCmdSQL& stCmd = *(CCmdSQL*)m_pstChild;
    if (stCmd.m_stResult.m_iOpType != MYSQL_SELECT)
    {
        CT_WARNING(("m_iResult = %d, m_iOpType = %d", stCmd.m_stResult.m_iResult, stCmd.m_stResult.m_iOpType));
        iRet = AnsResult(RET_SYSTEM_FAIL);
        return AnsClients(iRet);
    }

    if (stCmd.m_stResult.m_iResult != 0)     //查询失败
    {
        CT_WARNING((""));
        iRet = AnsResult(stCmd.m_stResult.m_iResult);
        return AnsClients(iRet);
    }

    if (stCmd.m_stResult.m_iRowCount == 0) //没有记录，直接返回0
    {
        stAns.iDataLen = 0;
        _bHasOtherData = false;
        _iFrom = 0;
        iRet = AnsResult(RET_NO_RECORDER);
        return AnsClients(iRet);
    }

    //结果处理
    iRet = HandleResult(stCmd);
    if (iRet != 0)
    {
        CT_ERROR(("HandleResult ret %d", iRet));
        iRet = AnsResult(RET_NO_RECORDER);
        return AnsClients(iRet);
    }

    return AnsClients(stCmd.m_stResult.m_iResult);
}

int CCmdSelectDataFromDB::AnsClients(int iRet)
{
    if (RET_OK == iRet && _bHasOtherData)
    {
        return iRet;
    }
    else
    {
        return Done(iRet);
    }
}

int CCmdSelectDataFromDB::AnsResult(int iRet)
{
    m_stMsgHead.shMsgType = CTLib::EMT_ANSWER;
    stAns.stResult.iResultID = iRet;

    CTCodeStream s(pstMainCtrl->m_stEncodeBuf);
    CodeConvert(s, m_stMsgHead, NULL, CTLib::bin_encode());
    CodeConvert(s, stAns, NULL, CTLib::bin_encode());

    if (iRet == RET_OK && stAns.iDataLen > 0)
    {
        memcpy(s.m_pszBuf + s.m_ushPos, szBuf, stAns.iDataLen);
        s.m_ushPos += stAns.iDataLen;
    }

    if (s.m_iRet != 0)
    {
        CT_WARNING((""));
        return RET_SYSTEM_FAIL;
    }

    //结果返回
    if (pstMainCtrl->AnswerToClient(m_stHead, s.m_pszBuf, s.m_ushPos) != 0)
    {
        CT_WARNING((""));
        return RET_SYSTEM_FAIL;
    }

    return iRet;
}

int CCmdSelectDataFromDB::BuildSql(CCmdSQL* pstCmd)
{
    int iRet = 0;
    switch(stReq.m_stKey.m_chDataType)
    {
    case DT_PLAYER_BASE_INFO:
        {
            iRet = CPlayerBaseInfoDB::BuildSelectSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), (unsigned int)stReq.m_stKey.m_u64ID);
        }
        break;
    case DT_PLAYER_GID:
        {
            CTSizeString<USER_TOKEN_LEN> szUserToken;
            szUserToken.Set("%s", stReq.m_stKey.m_sStrID());
            CT_TRACE(("szUserToken = %s", szUserToken()));
            iRet = CPlayerBaseInfoDB::BuildSelectGIDSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), szUserToken);
        }
        break;
    case DT_MAX_PLAYER_GID:
        {
            iRet = CPlayerBaseInfoDB::BuildSelectMaxGIDSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName());
        }
        break;
    case DT_PLAYER_DETAIL_INFO:
        {
            iRet = CPlayerDetailInfoDB::BuildSelectSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), (unsigned int)stReq.m_stKey.m_u64ID);
        }
        break;
    case DT_PLAYER_DETAIL_EX1_INFO:
        {
            iRet = CPlayerDetailInfoEx1DB::BuildSelectSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), (unsigned int)stReq.m_stKey.m_u64ID);
        }
        break;
    case DT_PLAYER_SNS_DETAIL_INFO:
        {
            iRet = CPlayerSnsDetailInfoDB::BuildSelectSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), (unsigned int)stReq.m_stKey.m_u64ID);
        }
        break;
    case DT_PLAYER_SNS_COMM_INFO:
        {
            iRet = CPlayerSnsCommInfoDB::BuildSelectSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), _iFrom);
        }
        break;
    case DT_PLAYER_SNS_COMM_INFO_COUNT:
        {
            iRet = CPlayerSnsCommInfoDB::BuildSelectCountSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName());
        }
        break;
    case DT_PLAYER_UNACT_PARTNER:
        {
            iRet = CUnactPartnerInfoDB::BuildSelectSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), (unsigned int)stReq.m_stKey.m_u64ID);
        }
        break;
    case DT_ARENA_RANK:
        {
            iRet = CArenaRankDB::BuildSelectSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), _iFrom);
        }
        break;
    case DT_ARENA_RANK_COUNT:
        {
            iRet = CArenaRankDB::BuildSelectCountSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName());
        }
        break;
    case DT_ZONE_COUNT:
        {
            iRet = CZoneDataDB::BuildSelectCountSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName());
        }
        break;
    case DT_ZONE_DATA:
        {
            iRet = CZoneDataDB::BuildSelectSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), (int)stReq.m_stKey.m_u64ID);
        }
        break;
    case DT_CLAN_DATA_COUNT:
        {
            iRet = CClanDataDB::BuildSelectCountSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName());
        }
        break;
    case DT_CLAN_DATA:
        {
            iRet = CClanDataDB::BuildSelectSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), _iFrom);
        }
        break;
    case DT_INSTANCE_ZONE_DETAIL_INFO:
        {
            iRet = CInstanceZoneDetailInfoDB::BuildSelectSQL(pstCmd->m_stReq, pstMainCtrl->m_szDBName(), (int)stReq.m_stKey.m_u64ID);
        }
        break;
    default:
        CT_TRACE(("unknow type %d", stReq.m_stKey.m_chDataType));
        return -1;
    }

    return iRet;
}

int CCmdSelectDataFromDB::HandleResult(CCmdSQL& stCmd)
{
    int iRet  = 0;

    CTCodeStream s(szBuf, sizeof(szBuf));
    switch(stReq.m_stKey.m_chDataType)
    {
    case DT_PLAYER_BASE_INFO:
        {
            CPlayerBaseInfo stPlayerBaseInfo;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, stPlayerBaseInfo);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_PLAYER_GID:
        {
            CGidList stGIDList;

            for (int i = 0; i < stCmd.m_stResult.m_iRowCount; ++i)
            {
                unsigned int uiGID = 0;
                s.InitConvert();

                CodeConvert(*stCmd.m_pstStream, uiGID, NULL, mysql_decode());
                if (stCmd.m_pstStream->m_iRet)
                {
                    CT_WARNING(("decode error: %d", stCmd.m_pstStream->m_iRet));
                    return stCmd.m_pstStream->m_iRet;
                }

                stGIDList._auiGID.AddOneItem(uiGID);
            }

            CodeConvert(s, stGIDList, NULL, bin_encode());
            if (s.m_iRet)
            {
                CT_WARNING(("encode error: %d", s.m_iRet));
                return s.m_iRet;
            }

            stAns.iDataLen = (int)s.m_ushPos;

            CTSizeString<USER_TOKEN_LEN> szUserToken;
            szUserToken.Set("%s", stReq.m_stKey.m_sStrID());
            int iIndex = CDBCtrl::m_pstMain->m_stUserTokenToGID.HashAlloc(szUserToken);
            if (iIndex >= 0)
            {
                CDBCtrl::m_pstMain->m_stUserTokenToGID[iIndex] = stGIDList;
            }
            iRet = AnsResult(iRet);
        }
        break;
    case DT_MAX_PLAYER_GID:
        { 
            int64 i64MaxGID;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, i64MaxGID);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_PLAYER_DETAIL_INFO:
        {
            CPlayerDetailInfo stPlayerDetailInfo;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, stPlayerDetailInfo);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_PLAYER_DETAIL_EX1_INFO:
        {
            CPlayerDetailInfoEx1 stPlayerDetailInfoEx1;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, stPlayerDetailInfoEx1);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_PLAYER_SNS_DETAIL_INFO:
        {
            CPlayerSnsDetailInfo stPlayerSnsDetailInfo;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, stPlayerSnsDetailInfo);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_PLAYER_SNS_COMM_INFO:
        {
            for (int i = 0; i < stCmd.m_stResult.m_iRowCount; ++i)
            {
                CPlayerSnsCommInfo stPlayerSnsCommInfo;
                s.InitConvert();
                iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, stPlayerSnsCommInfo);
                stAns.iDataLen = (int)s.m_ushPos;
                iRet = AnsResult(iRet);
                CHECK_RETURN(iRet);

                _iFrom++;
            }

            if (CPlayerSnsCommInfoDB::SELECT_PLAYER_SNS_COMM_INFO_COUNT_PER_TIME 
                            == stCmd.m_stResult.m_iRowCount)
            {
                _bHasOtherData = true;
                iRet = SendSql();
            }
            else
            {
                _iFrom = 0;
                _bHasOtherData = false;
            }
        }
        break;
    case DT_PLAYER_SNS_COMM_INFO_COUNT:
        {
            int64 i64Count = 0;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, i64Count);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_PLAYER_UNACT_PARTNER:
        {
            CUnactPartnerInfo stUnactPartnerInfo;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, stUnactPartnerInfo);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_ARENA_RANK_COUNT:
        {
            int64 i64Count = 0;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, i64Count);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_ARENA_RANK:
        {
            for (int i = 0; i < stCmd.m_stResult.m_iRowCount; ++i)
            {
                CArenaRank stArenaRank;
                s.InitConvert();
                iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, stArenaRank);
                stAns.iDataLen = (int)s.m_ushPos;
                iRet = AnsResult(iRet);
                CHECK_RETURN(iRet);

                _iFrom++;
            }

            if (CArenaRankDB::SELECT_ARENA_RANK_COUNT_PER_TIME
                                 == stCmd.m_stResult.m_iRowCount)
            {
                _bHasOtherData = true;
                iRet = SendSql();
            }
            else
            {
                _iFrom = 0;
                _bHasOtherData = false;
            }
        }
        break;
    case DT_ZONE_COUNT:
        {
            int64 i64Count = 0;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, i64Count);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_ZONE_DATA:
        {
            CZoneData stZoneData;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, stZoneData);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_CLAN_DATA_COUNT:
        {
            int64 i64Count = 0;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, i64Count);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    case DT_CLAN_DATA:
        {
            for (int i = 0; i < stCmd.m_stResult.m_iRowCount; ++i)
            {
                CClanData stClanData;
                s.InitConvert();
                iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, stClanData);
                stAns.iDataLen = (int)s.m_ushPos;
                iRet = AnsResult(iRet);
                CHECK_RETURN(iRet);

                _iFrom++;
            }

            if (CClanDataDB::SELECT_CLAN_DATA_COUNT_PER_TIME
                == stCmd.m_stResult.m_iRowCount)
            {
                _bHasOtherData = true;
                iRet = SendSql();
            }
            else
            {
                _iFrom = 0;
                _bHasOtherData = false;
            }
        }
        break;
    case DT_INSTANCE_ZONE_DETAIL_INFO:
        {
            CInstanceZoneDetailInfo stInstanceZoneDetailInfo;
            iRet = pstMainCtrl->FromMysqlEncodeToBinEncode(*stCmd.m_pstStream, s, stInstanceZoneDetailInfo);
            stAns.iDataLen = (int)s.m_ushPos;
            iRet = AnsResult(iRet);
        }
        break;
    default:
        break;
    }
 
    return iRet;
}

